//: src/com/silvtar/sync/model/SilverySyncInit.java
/* 
 * Created by 朴晟宁 <piaosn@gmail.com> on 5/26/2013. 
 * Copyright (c) 2013 朴晟宁. All rights reserved.
 * 
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program;
 * 
 * *********************************************************************
 * 
 * Modify History:
 * Date        Version    Description
 * 5/26/2013   0.1        Create the class.
 * 5/28/2013   0.2        Add the trigger support.
 * 5/31/2013   0.3        Make one trigger can only start one rsync process.
 * 6/ 5/2013   0.4        Add Isync support to App.
 */
package com.silvtar.sync.controller;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import com.silvtar.io.StdOut;
import com.silvtar.isync.SSIsync;
import com.silvtar.isync.SSIsyncDaemon;
import com.silvtar.rsync.SSRsync;
import com.silvtar.rsync.SSRsyncDaemon;
import com.silvtar.sync.model.SSTrigger;
import com.silvtar.sync.model.SyncItem;
import com.silvtar.util.Bin;
import com.silvtar.util.SSPlatform;
import com.silvtar.util.SSProfileMD;

/**
 * 程序的初始化类
 * 
 * @author 朴晟宁/Silvtar
 * @author piaosn@gmail.com
 * @version 0.3
 */
public class SilverySyncInit {

    static final int TRANSISYNC = 1;
    static final int TRANSFTP = 2;
    static final int TRANSRSYNC = 3;
    
    
    static boolean syncing = false;
    // 主机信息

    
    // 配置项 - 主配置
    private String                             ipAddr;               // 对方IP地址
    private int                                config_port;          // 控制器端口
    private int                                way_to_sync;          // 同步方式

    // 配置项 - 配置
    private int                                validator_port;       // 验证器端口
    private String                             validator_key_path;   // 验证密钥配置文件目录

    // 配置项 - rsync配置
    private String                             sync_item_config_path; // rsync同步文件夹项目配置文件
    private String                             rsync_root_path;      // rsync根目录
    private int                                rsync_port;           // rsync端口
    private String                             uid;                  // 用户名
    private String                             passwd;               // 密码
    
    // 配置项 - isync配置
    private int                                inner_sync_command_port;
    private int                                inner_transporter_command_port;
    private int                                inner_transporter_data_port;
    
    // 持有对象
    private SSRsyncDaemon                      ssRsyncDaemon;
    private SSRsync                            ssRsync;
    private SSIsyncDaemon                      ssIsyncDaemon;
    private SSIsync                            ssIsync;
    private SSValidator                        ssValidator;

    // 共有数据
    private LinkedHashMap<SSTrigger, SyncItem> triggerMap;           // 存放有触发器
    private LinkedList<SyncItem>               syncItems;            // 同步文件夹

    // 服务状态
    private boolean                            rsyncdOn    = false;  // rsync服务器是否已经启动
    private boolean                            isyncdOn    = false;  // isync服务器是否已经启动
    private boolean                            validatorOn = false;  // 验证器服务器是否已经启动

    // 服务pid
    private int                                rsyncdPid   = -1;     // rsync服务器的pid

    // -----------------------------------------------------------------
    public boolean isIsyncOn() {
        return isyncdOn;
    }
    
    public boolean isRsyncdOn() {
        return rsyncdOn;
    }

    public boolean isValidatorOn() {
        return validatorOn;
    }

    
    public LinkedHashMap<SSTrigger, SyncItem> getTriggerMap() {
        return triggerMap;
    }

    
    public void refreshDaemonState() {
        // isync
        if (ssIsyncDaemon == null) {
            isyncdOn = false;
        } else {
            isyncdOn = true;
        }
        // rsync
        if (SSPlatform.platform == SSPlatform.MAC || SSPlatform.platform == SSPlatform.LINUX) {
            rsyncdPid = Bin.searchProcess("rsync");
            if (rsyncdPid >= 0) {
                rsyncdOn = true;
            } else {
                rsyncdOn = false;
            }
            
        }
        
    }

    public SilverySyncInit() {
        
        
        triggerMap = new LinkedHashMap<SSTrigger, SyncItem>();

        ssValidator = new SSValidator();
        
        
        if (SSPlatform.platform != SSPlatform.ANDROID) {
            // 先读取主配置文件
            configSilverySync();

            // rsyncd的passwd配置

            // rsync的passwd配置

            // 获取服务状态
            refreshDaemonState();

            // 验证
            startValidateDaemon();

            // 读取sync文件夹配置文件
            readSyncPathProfile();

            // 配置触发器
            configTrigger();
        }
        
    }

    /**
     * 读取主配置文件
     */
    public void configSilverySync() {
        SSProfileMD pfMD = new SSProfileMD("./assets/config.md");
        SSProfileMD.PfItem pfItem = null;
        String key = null;
        String parameter = null;
        StdOut.printLog("开始读取主配置文件...\n 路径：./assets/config.md");
        while ((pfItem = pfMD.getNextItem()) != null) {
            key = pfItem.getKey();
            parameter = pfItem.getParameter();

            StdOut.printLog("    " + key + " = " + parameter);
            // 主程序配置
            if (key.equals("ip_addr")) {
                ipAddr = parameter;
            } else if (key.equals("config_port")) {
                config_port = Integer.parseInt(parameter);
            } else if (key.equals("way_to_sync")) {
                way_to_sync = Integer.parseInt(parameter);
            }
            // 验证器配置
            else if (key.equals("validator_port")) {
                validator_port = Integer.parseInt(parameter);
            } else if (key.equals("validator_key_path")) {
                validator_key_path = parameter;
            }
            // rsync配置
            else if (key.equals("sync_item_config_path")) {
                sync_item_config_path = parameter;
            } else if (key.equals("rsync_root_path")) {
                rsync_root_path = parameter;
            } else if (key.equals("rsync_port")) {
                rsync_port = Integer.parseInt(parameter);
            } else if (key.equals("uid")) {
                uid = parameter;
            } else if (key.equals("passwd")) {
                passwd = parameter;
            }
            // isync配置
            else if (key.equals("inner_sync_command_port")) {
                inner_sync_command_port = Integer.parseInt(parameter);
            } else if (key.equals("inner_transporter_command_port")) {
                inner_transporter_command_port = Integer.parseInt(parameter);
            } else if (key.equals("inner_transporter_data_port")) {
                inner_transporter_data_port = Integer.parseInt(parameter);
            } 
        }
        pfMD.close();
        StdOut.printLog("主配置文件读取完毕。\n");
    }

    /**
     * 读取同步目录配置文件
     */
    public void readSyncPathProfile() {
        // 初始化<同步目录链表>，因为每次调用这个函数时都是在希望刷新目录的时候
        syncItems = new LinkedList<SyncItem>();

        // 配置文件读取器与临时的键值对
        SSProfileMD pfMD = new SSProfileMD(sync_item_config_path);
        SSProfileMD.PfItem pfItem = null;
        String key = null;
        String value = null;
        SyncItem tempItem = null;

        // 开始读取配置文件
        StdOut.printLog("\n 开始读取sync_item.md... \n 路径：" + sync_item_config_path);
        while ((pfItem = pfMD.getNextItem()) != null) {
            key = pfItem.getKey();
            value = pfItem.getParameter();
            StdOut.printLog("    " + key + " = " + value);

            if (key.equals("local_path")) {
                if (tempItem != null) {
                    syncItems.add(tempItem);
                }
                tempItem = new SyncItem(value);
            } else if (key.equals("remote_path")) {
                tempItem.setRemotePath(value);
            } else if (key.equals("listen")) {
                if (!value.equals("false")) {
                    tempItem.setListenReturnTime(Integer.parseInt(value));
                }
            } else if (key.equals("moment")) {
                tempItem.setMoment(value);
            } else if (key.equals("interval")) {
                if (!value.equals("false")) {
                    tempItem.setInterval(value);
                }
            } else {
                StdOut.printLog("位置选项:" + key);
            }
        }
        if (tempItem != null) {
            syncItems.add(tempItem);
        }

    }

    /**
     * 配置触发器
     */
    public void configTrigger() {
        StdOut.println();
        for (Iterator iterator = syncItems.iterator(); iterator.hasNext();) {
            SyncItem tempItem = (SyncItem) iterator.next();
            SSTrigger tempTrigger = new SSTrigger(this);
            triggerMap.put(tempTrigger, tempItem);
            
            if (tempItem.isUsingInterval()) {
                tempTrigger.setInterval(tempItem.getInterval());
                StdOut.printLog(" 为目录：" + tempItem.getLocalPath()
                        + "添加时间间隔触发器。间隔时间为" + tempItem.getInterval() + "秒");
            }
            if (tempItem.isUsingMoment()) {

            }
            if (tempItem.isListen()) {
                tempTrigger.setMonitor(tempItem.getLocalPath(), tempItem.getListenReturnTime());
                StdOut.printLog(" 为目录：" + tempItem.getLocalPath()
                        + "添加文件夹监视器。同步动作会在文件夹被修改后的" + tempItem.getListenReturnTime() + "秒后启动");
            }

        }
    }

    public void startSyncAll() {
        switch (way_to_sync) {
        case TRANSISYNC:
            startIsyncAll();
            break;
        case TRANSFTP:
            
            break;
        case TRANSRSYNC:
            startRsyncAll();
            break;
        default:
            break;
        }
    }
    public void startSync(SSTrigger trigger) {
        switch (way_to_sync) {
        case TRANSISYNC:
            startIsync(trigger);
            break;
        case TRANSFTP:
            
            break;
        case TRANSRSYNC:
            startRsync(trigger);
            break;
        default:
            break;
        }
    }
    
    public void startSync(SyncItem syncItem) {
        while (syncing) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        syncing = true;
        
        switch (way_to_sync) {
        case TRANSISYNC:
            startIsync(syncItem);
            break;
        case TRANSFTP:
            
            break;
        case TRANSRSYNC:
            startRsync(syncItem);
            break;
        default:
            break;
        }
    }
    
    public void startSyncDaemon() {
        switch (way_to_sync) {
        case TRANSISYNC:
            startIsyncDaemon();
            break;
        case TRANSFTP:
            
            break;
        case TRANSRSYNC:
            startRsyncDaemon();
            break;
        default:
            break;
        }
    }
    // ------------------------------Isync部分------------------------------
    public void configIsyncDaemon() {
        if (ssIsyncDaemon == null) {
            ssIsyncDaemon = new SSIsyncDaemon();
            ssIsyncDaemon.configIsyncDaemon(inner_sync_command_port, inner_transporter_command_port, inner_transporter_data_port);
        }
    }
    
    /**
     * 开启isync daemon
     */
    public void startIsyncDaemon() {
        refreshDaemonState();
        configIsyncDaemon();
        if (isyncdOn) {
            StdOut.printLog("Isync daemon已经启动。");
        } else {
            StdOut.printLog("启动Rsync daemon...");
            ssIsyncDaemon.startIsyncDaemon();
            isyncdOn = true;
        }
        StdOut.printLog("");
    }
    
    /**
     * 配置isync client
     */
    public void configIsync() {
        ssIsync = new SSIsync();
        ssIsync.configIsync(ipAddr, inner_sync_command_port, inner_transporter_command_port, inner_transporter_data_port);
    }
    
    /**
     * 开始与触发器绑定的isync过程
     * 
     * @param trigger
     *            触发器
     */
    public void startIsync(SSTrigger trigger) {
        startIsync(triggerMap.get(trigger));
    }
    
    /**
     * 开始rsync同步过程
     */
    public void startIsync(SyncItem syncItem) {
        //检查本次的传输方式
        if (way_to_sync != TRANSISYNC) {
            StdOut.printLog(" 本次传输不应使用inner sync，如果确实需要inner sync同步，请修改配置文件并点击<重载配置文件>。");
            return;
        }
        
        // 判断是否配置过Isync客户端
        configIsync();
        
        // 检查对方是否经过验证
        StdOut.printLog("\n 检查对方是否已验证...");
        if (!ssValidator.isSuccess()) {
            StdOut.println("您还没有与对方进行配对。请先进行配对。");
            return;
        }

        // 开始同步
        StdOut.printLog("    正在同步：" + syncItem.getLocalPath() + " ："
                + syncItem.getRemoteModel());
        ssIsync.startIsync(syncItem.getLocalPath(), syncItem.getRemotePath());
    }
    
    /**
     * 开始rsync同步过程
     */
    public void startIsyncAll() {
        //检查本次的传输方式
        if (way_to_sync != TRANSISYNC) {
            StdOut.printLog(" 本次传输不应使用inner sync，如果确实需要inner sync同步，请修改配置文件并点击<重载配置文件>。");
            return;
        }
        
        // 判断是否配置过Isync客户端
        configIsync();
        
        // 检查对方是否经过验证
        StdOut.printLog("\n 检查对方是否已验证...");
        if (!ssValidator.isSuccess()) {
            StdOut.println("您还没有与对方进行配对。请先进行配对。");
            return;
        }

        // 开始同步
        StdOut.printLog("\n 开始Isync同步...");
        for (Iterator iterator = syncItems.iterator(); iterator.hasNext();) {
            SyncItem tempItem = (SyncItem) iterator.next();
            StdOut.printLog("    正在同步：" + tempItem.getLocalPath() + " ："
                    + tempItem.getRemotePath());
            ssIsync.startIsync(tempItem.getLocalPath(),
                    tempItem.getRemotePath());
        }
    }
    
    // ------------------------------Rsync部分------------------------------
    /**
     * 根据配置文件配置rsync daemon
     */
    public void configRsyncDaemon() {

        // 判断是否读取过<同步文件夹>配置文件
        if (syncItems == null) {
            readSyncPathProfile();
        }
        
        if (ssRsyncDaemon == null) {
            ssRsyncDaemon = new SSRsyncDaemon();
        }
        
        StdOut.printLog("\n 开始配置rsync daemon...");

        // rsyncd的配置
        ssRsyncDaemon.configRsyncDaemon(uid, uid, uid, rsync_root_path, rsync_port);

        // 开始写入rsyncd配置文件
        StdOut.printLog("\n 开始写入rsyncd配置文件...");
        for (Iterator iterator = syncItems.iterator(); iterator.hasNext();) {
            SyncItem tempItem = (SyncItem) iterator.next();
            StdOut.printLog(" 目录：" + tempItem.getLocalPath());
            ssRsyncDaemon.writeItem(tempItem.getLocalPath());
        }

        StdOut.printLog("rsyncd配置文件写入完毕。\n");
    }

    /**
     * 开启rsync daemon
     */
    public void startRsyncDaemon() {
        refreshDaemonState();
        configRsyncDaemon();
        if (rsyncdOn) {
            StdOut.printLog("Rsync daemon已经启动。");
        } else {
            StdOut.printLog("启动Rsync daemon...");
            ssRsyncDaemon.startRsyncDaemon();
            rsyncdOn = true;
        }
        StdOut.printLog("");
    }

    /**
     * 配置rsync client
     */
    public void configRsync() {
        ssRsync = new SSRsync();
        ssRsync.configRsync(uid, ipAddr, rsync_port);
    }

    /**
     * 开始与触发器绑定的rsync过程
     * 
     * @param trigger
     *            触发器
     */
    public void startRsync(SSTrigger trigger) {
        startRsync(triggerMap.get(trigger));
    }

    /**
     * 开始rsync同步过程
     */
    public void startRsync(SyncItem syncItem) {
        //检查本次的传输方式
        if (way_to_sync != TRANSRSYNC) {
            StdOut.printLog(" 本次传输不应使用rsync，如果确实需要rsync同步，请修改配置文件并点击<重载配置文件>。");
            return;
        }
        
        // 判断是否配置过Rsync客户端
        if (ssRsync == null) {
            configRsync();
        }

        // 检查对方是否经过验证
        StdOut.printLog("\n 检查对方是否已验证...");
        if (!ssValidator.isSuccess()) {
            StdOut.println("您还没有与对方进行配对。请先进行配对。");
            return;
        }

        // 开始同步
        StdOut.printLog("    正在同步：" + syncItem.getLocalPath() + " 模块："
                + syncItem.getRemoteModel());
        ssRsync.startRsync(syncItem.getLocalPath(), syncItem.getRemoteModel());
    }

    /**
     * 开始全部rsync同步过程,同步所有文件夹。
     */
    public void startRsyncAll() {
        //检查本次的传输方式
        if (way_to_sync != TRANSRSYNC) {
            StdOut.printLog(" 本次传输不应使用rsync，如果确实需要rsync同步，请修改配置文件并点击<重载配置文件>。");
            return;
        }
        // 判断是否配置过Rsync客户端
        if (ssRsync == null) {
            configRsync();
        }

        // 判断是否读取过<同步文件夹>配置文件
        if (syncItems == null) {
            readSyncPathProfile();
        }

        // 检查对方是否经过验证
        StdOut.printLog("\n 检查对方是否已验证...");
        if (!ssValidator.isSuccess()) {
            StdOut.println("您还没有与对方进行配对。请先进行配对。");
            return;
        }

        // 开始同步
        StdOut.printLog("\n 开始Rsync同步...");
        for (Iterator iterator = syncItems.iterator(); iterator.hasNext();) {
            SyncItem tempItem = (SyncItem) iterator.next();
            StdOut.printLog("    正在同步：" + tempItem.getLocalPath() + " 模块："
                    + tempItem.getRemoteModel());
            ssRsync.startRsync(tempItem.getLocalPath(),
                    tempItem.getRemoteModel());
        }
    }

    // ------------------------------验证器部分------------------------------
    /**
     * 配置验证器服务
     */
    public void configValidateDaemon() {
        // 服务端配置
        SSProfileMD pfMD = new SSProfileMD(validator_key_path);
        SSProfileMD.PfItem pfItem = null;
        String key = null;
        String parameter = null;

        ssValidator.configDaemon(validator_port);
        StdOut.printLog("开始读取validate.md... \n 路径：" + validator_key_path);
        while ((pfItem = pfMD.getNextItem()) != null) {
            key = pfItem.getKey();
            parameter = pfItem.getParameter();

            StdOut.printLog("    " + key + " = " + parameter);
            if (key.equals("validate_key")) {
                ssValidator.setValidateKey(parameter);
                break;
            }
        }

        // 客户端配置
        StdOut.printLog("验证器服务配置完毕\n");
    }

    /**
     * 配置验证器客户端
     */
    public void configValidateClient() {
        ssValidator.configClient(ipAddr);
    }

    /**
     * 开始验证服务
     */
    public void startValidateDaemon() {
        configValidateDaemon();
        if (validatorOn) {
            StdOut.printLog("重新启动验证服务器...");
            ssValidator.startValidateDaemon();
        } else {
            StdOut.printLog("启动验证服务器...");
            ssValidator.startValidateDaemon();
            validatorOn = true;
        }
        StdOut.printLog("");
    }

    /**
     * 进行验证
     * 
     * @return
     */
    public boolean startValidate() {
        configValidateClient();
        return ssValidator.validate();
    }

    /**
     * 查看是否验证过
     * 
     * @return
     */
    public boolean isValidated() {
        return ssValidator.isSuccess();
    }
}
